package com.sfx.concurrent.demo.concurrent.BlockingQueueTest;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: sfx
 * Date: 2023-03-17
 * Time: 14:27
 */
public class MyBlockingQueueDoubleCheck1<T> {
    private final T[] queue;//使用队列作为数组
    private int capacity;//数组容量
    private AtomicInteger size;//队列实际有效元素个数
    private int head,tail;//对头,队尾
    public MyBlockingQueueDoubleCheck1(int capacity) {
        this.capacity = capacity;
        this.size =new AtomicInteger(0);
        queue = (T[]) new Object[capacity];
    }

    private static final ReentrantLock headLock = new ReentrantLock();
    private static final ReentrantLock tailLock = new ReentrantLock();

    private static final Condition headCondition = headLock.newCondition();
    private static final Condition tailCondition = tailLock.newCondition();

    //offer方法
    public void offer(T t) throws InterruptedException {
        tailLock.lockInterruptibly();
        int c;
        try {
            while(isFull()) {
                tailCondition.await();
            }
            queue[tail] = t;
            if(++tail == this.capacity) {
                tail = 0;
            }
            c = size.getAndIncrement();
            if(c + 1 < queue.length) {
                headCondition.signal();
            }
        }finally {
            tailLock.unlock();
        }
        headLock.lock();
        if(c == 0) {
            try{
                headCondition.signal();
            }finally {
                headLock.unlock();
            }
        }
    }

    //pool方法
    public T pool() throws InterruptedException {
        int c;
        headLock.lockInterruptibly();
        T val;
        try{
            while(isEmpty()) {
                headCondition.await();
            }
            val = queue[head];
            queue[head] = null;//加快GC
            if(++head == this.capacity) {
                head = 0;
            }
            c = size.getAndDecrement();
            if(c>1) {
                headCondition.signal();
            }
        }finally {
            headLock.unlock();
        }
        tailLock.lock();
        if(c == queue.length) {
            try{
                tailCondition.signal();
            }finally {
                tailLock.unlock();
            }
        }
        return val;
    }
    private boolean isFull() {
        return this.size.get() == this.capacity;
    }
    private boolean isEmpty() {
        return this.size.get() == 0;
    }
}